<?php
namespace core\models;
/**
 * 授权令牌类
 * Class Token_Jwt
 * @author 李文凯 <1275124829@163.com>
 * @date   2020-09-24 15:48
 */
class Token_Jwt {

    /**
     * 加密的密钥
     * @var string
     * @date   2020-09-24
     */
    public $key = 'token_string_acyi*1Y5.Cs8@&^T123.';

    /**
     * 授权令牌有效期 单位秒
     * @var int
     * @date   2020-09-24
     */
    public $token_life_time = \config_web::SESSION_LIFE_TIME;

    /**
     * 生成JWT
     * @param array $payload $payload=[iss'=>'签发者','iat' => $_SERVER['REQUEST_TIME']什么时候签发的,'exp' => $_SERVER['REQUEST_TIME'] + 7200过期时间,'uid'=>用户ID]
     * @param string $key 加密密钥
     * @param string $alg 加密方式
     * @return string
     */
    public function encode(array $payload, string $key, string $alg = 'SHA256')
    {
        $key = md5($key);
        $jwt = $this->urlsafeB64Encode(json_encode(['typ' => 'JWT', 'alg' => $alg])) . '.' . $this->urlsafeB64Encode(json_encode($payload));
        return $jwt . '.' . $this->signature($jwt, $key, $alg);
    }

    /**
     * 生成签名
     * @param string $input
     * @param string $key
     * @param string $alg
     * @return string
     */
    private function signature(string $input, string $key, string $alg)
    {
        return hash_hmac($alg, $input, $key);
    }

    /**
     * 解析并验证令牌，过期返回 false
     * @param string $jwt TOKEN令牌
     * @param string $key TOKEN密钥
     * @return bool|mixed
     */
    public function decode(string $jwt, string $key)
    {
        $tokens = explode('.', $jwt);
        $key = md5($key);

        if (count($tokens) != 3)
            return false;

        list($header64, $payload64, $sign) = $tokens;

        $header = json_decode($this->urlsafeB64Decode($header64), JSON_OBJECT_AS_ARRAY);
        if (empty($header['alg']))
            return false;

        if ($this->signature($header64 . '.' . $payload64, $key, $header['alg']) !== $sign)
            return false;

        $payload = json_decode($this->urlsafeB64Decode($payload64), JSON_OBJECT_AS_ARRAY);

        $time = $_SERVER['REQUEST_TIME'];
        if (isset($payload['iat']) && $payload['iat'] > $time)
            return false;

        if (isset($payload['exp']) && $payload['exp'] < $time)
            return false;

        return $payload;
    }

    /**
     * @param string $input
     * @return bool|string
     */
    private function urlsafeB64Decode(string $input)
    {
        $remainder = strlen($input) % 4;

        if ($remainder) {
            $padlen = 4 - $remainder;
            $input .= str_repeat('=', $padlen);
        }

        return base64_decode(strtr($input, '-_', '+/'));
    }


    /**
     * @param string $input
     * @return mixed
     */
    private function urlsafeB64Encode(string $input)
    {
        return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
    }
}